package com.tunan.system.dic.web;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.contant.Status;
import com.exception.InvalidParameterMainError;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.tunan.common.Result;
import com.tunan.common.ResultFormUtils;
import com.tunan.common.resultSub.ResultSuccess;
import com.tunan.common.resultSub.ResultWithPage;
import com.tunan.config.FilePathConfig;
import com.tunan.system.dic.service.IBscDicCodeService;
import com.tunan.system.persistence.model.BscDicCodeItem;
import com.tunan.system.persistence.model.BscDicCodeType;
import com.tunan.utils.BasicCombo;
import com.tunan.utils.BscDicCodeConverter;
import com.tunan.utils.JsonUtils;
import com.tunan.utils.Plupload;
import com.tunan.utils.PluploadUtil;
import com.tunan.utils.ValidationUtils;

/**
 * 数据字典控制类
 */
@Controller
@RequestMapping(value = "/BscDicCode")
public class BscDicCodeController {

	private static Logger logger = LoggerFactory.getLogger(BscDicCodeController.class);

	/**
	 * 缓冲大小
	 */
	private static final int BUFFER_SIZE = 2048;

	/**
	 * 上传的文件保存在服务器上的文件名
	 */
	private static final String UPLOAD_FILE_NAME = "dicCodeExcel.xls";

	/**
	 * 上传文件保存的文件夹名称
	 */
	private static final String UPLOAD_FILE_FOLDER = "uploadDicCodeExcel";

	@Autowired
	private IBscDicCodeService bscDicCodeService;


	@Autowired
	private FilePathConfig filePathConfig;

	/**
	 * 进入主页面
	 * 
	 * @return 跳转页面
	 */
	@RequestMapping(value = "/index", method = RequestMethod.GET)
	public ModelAndView bscDicCodeIndex() {
		return new ModelAndView("/system/systemDictionaryList");
	}

	/**
	 * 分页查询数据字典类型
	 * 
	 * @param typeKeyword
	 *            查询关键字，允许为NULL
	 * @param pager
	 *            分页对象
	 * @return 字典类型分页查询结果
	 * @throws Exception
	 */
	@RequestMapping(value = "/pfindTypes.do")
	public Page pfindTypes(String typeKeyword, @ModelAttribute("pageParams") Page pageParams) throws Exception {
		try {
			PageHelper.startPage(pageParams.getPageNum(), pageParams.getPageSize());
			Page pageresult = (Page) bscDicCodeService.pfindTypes(typeKeyword);
			return pageresult;
		} catch (Exception e) {
			logger.error("分页查询字典类型出错，查询关键字为{}。", typeKeyword);
			throw e;
		}
	}

	/**
	 * 加载数据字典类型对象
	 * 
	 * @param typeId
	 *            类型主键
	 * @return jsp页面地址
	 * @throws Exception
	 */
	@RequestMapping(value = "/inputType")
	public String inputType(String typeId, Model model) throws Exception {
		try {
			BscDicCodeType type = null;

			if (typeId != null && typeId.trim().length() > 0) {
				type = bscDicCodeService.getTypeByTypeId(typeId);
			} else {
				type = new BscDicCodeType();
			}
			model.addAttribute("vo", type);
			return "/system/addDicType";
		} catch (Exception e) {
			logger.error("加载字典类型出错，类型主键为：{}。", typeId);
			throw e;
		}
	}

	/**
	 * 保存字典类型form对象
	 * 
	 * @param form
	 *            字典类型form对象
	 * @param result
	 *            form对象验证结果
	 * @return Result对象
	 * @throws Exception
	 */
	@RequestMapping(value = "/saveType")
	@ResponseBody
	public Result saveType(@Valid BscDicCodeType form, BindingResult result, String oldtypeCode) throws Exception {
		try {
			if (result.hasErrors())
				throw new InvalidParameterMainError(result);
			bscDicCodeService.saveType(form, oldtypeCode);
			return ResultFormUtils.getSuccess("保存字典类型成功");
		} catch (Exception e) {
			logger.error("保存字典类型出错，form对象为：{}。", JsonUtils.toJson(form));
			throw e;
		}
	}

	/**
	 * 根据类型主键删除类型对象
	 * 
	 * @param typeId
	 *            类型主键
	 * @throws Exception
	 */
	@RequestMapping(value = "/deleteTypeCascade")
	@ResponseBody
	public Result deleteTypeCascade(String typeId) throws Exception {
		try {
			bscDicCodeService.deleteTypeCascadeByTypeId(typeId);
			return ResultFormUtils.getSuccess("删除字典类型成功！");
		} catch (Exception e) {
			logger.error("删除字典类型出错，类型主键：{}。", typeId);
			throw e;
		}
	}

	/**
	 * 删除多个未锁定的字典类型
	 */
	@RequestMapping(value = "/deleteTypes.do")
	@ResponseBody
	public Result deleteTypes(String[] typeIds) throws Exception {
		try {
			bscDicCodeService.deleteTypes(typeIds);
			return ResultFormUtils.getSuccess();
		} catch (Exception e) {
			logger.error("删除字典类型出错。");
			throw e;
		}
	}

	/**
	 * 启用字典类型
	 * 
	 * @param typeId
	 *            类型主键
	 * @throws Exception
	 */
	@RequestMapping(value = "/enableType.do")
	@ResponseBody
	public Result enableType(String typeId) throws Exception {
		try {
			bscDicCodeService.updateTypeIsActiveField(typeId, Status.ONE);
			return ResultFormUtils.getSuccess();
		} catch (Exception e) {
			logger.error("启用字典类型出错，类型主键为：{}。", typeId);
			throw e;
		}
	}

	/**
	 * 禁用字典类型
	 * 
	 * @param typeId
	 *            类型主键
	 * @throws Exception
	 */
	@RequestMapping(value = "/disableType.do")
	@ResponseBody
	public Result disableType(String typeId) throws Exception {
		try {
			bscDicCodeService.updateTypeIsActiveField(typeId, Status.ZERO);
			return ResultFormUtils.getSuccess();
		} catch (Exception e) {
			logger.error("禁用字典类型出错，类型主键为：{}。", typeId);
			throw e;
		}
	}

	/**
	 * 根据数据字典类型ID获取一个树
	 * 
	 * @param typeId
	 *            数据字典类型ID
	 * @return 数据字典类型树对象，包含所有子孙节点
	 */
	@RequestMapping(value = "/tgetTypeAllByTypeId.do")
	@ResponseBody
	public BscDicCodeType tgetTypeAllByTypeId(String typeId) throws Exception {
		try {
			BscDicCodeType form = bscDicCodeService.tgetTypeAllByTypeId(typeId);
			return form != null ? form : new BscDicCodeType();
		} catch (Exception e) {
			logger.error("获取类型树结构对象出错，类型主键为：{}。", typeId);
			throw e;
		}
	}

	/**
	 * 获取类型树结构对象
	 * 
	 * @param typeCode
	 *            类型编号
	 * @return 类型树结构对象
	 * @throws Exception
	 */
	@RequestMapping(value = "/tgetTypeAllByTypeCode.do")
	@ResponseBody
	public BscDicCodeType tgetTypeAllByTypeCode(String typeCode) throws Exception {
		try {
			BscDicCodeType form = bscDicCodeService.tgetTypeAllByTypeCode(typeCode);
			return form != null ? form : new BscDicCodeType();
		} catch (Exception e) {
			logger.error("获取类型树结构对象出错，类型编号为：{}。", typeCode);
			throw e;
		}
	}

	/**
	 * 获取类型树结构对象
	 * 
	 * @param typeId
	 *            类型ID
	 * @return 类型树结构对象
	 * @throws Exception
	 */
	@RequestMapping(value = "/tgetTypeActiveByTypeId.do")
	@ResponseBody
	public BscDicCodeType tgetTypeActiveByTypeId(String typeId) throws Exception {
		try {
			BscDicCodeType form = bscDicCodeService.tgetTypeActiveByTypeId(typeId);
			return form != null ? form : new BscDicCodeType();
		} catch (Exception e) {
			logger.error("获取类型树结构对象出错，类型主键为：{}。", typeId);
			throw e;
		}
	}

	/**
	 * 获取类型树结构对象
	 * 
	 * @param typeCode
	 *            类型编号
	 * @return 类型树结构对象
	 * @throws Exception
	 */
	@RequestMapping(value = "/tgetTypeActiveByTypeCode.do")
	@ResponseBody
	public BscDicCodeType tgetTypeActiveByTypeCode(String typeCode) throws Exception {
		try {
			BscDicCodeType form = bscDicCodeService.tgetTypeActiveByTypeCode(typeCode);
			return form != null ? form : new BscDicCodeType();
		} catch (Exception e) {
			logger.error("获取类型树结构对象出错，类型编号为：{}。", typeCode);
			throw e;
		}
	}

	/**
	 * 分页条件查询数据字典子项对象
	 * 
	 * @param typeId
	 *            字典类型主键，不允许为NULL
	 * @param itemKeyword
	 *            查询关键字，允许为NULL
	 * @param pager
	 *            分页对象
	 * @return 数据字典子项分页查询结果
	 * @throws Exception
	 */
	@RequestMapping(value = "/pfindItems")
	@ResponseBody
	public Result pfindItems(HttpServletResponse response, String typeCode, String itemKeyword,
			@ModelAttribute("pageParams") Page pageParams, String wfdsItem) throws Exception {
		List<BscDicCodeItem> itemslist = new ArrayList<BscDicCodeItem>();
		try {
			PageHelper.startPage(pageParams.getPageNum(), pageParams.getPageSize());
			if (typeCode == null || typeCode.trim().length() == 0) {

				Map<String, Object> params = new HashMap<String, Object>();
				params.put("wfdsItem", wfdsItem);
				itemslist = bscDicCodeService.getAllItems(params);
			} else {
				itemslist = bscDicCodeService.pfindItems(typeCode, wfdsItem);
			}
			// ObjectMapper mapper = new ObjectMapper();
			// String jsonfromMap = mapper.writeValueAsString(itemslist);
			// response.getWriter().write(jsonfromMap);

			Result result = new ResultWithPage<BscDicCodeItem>(itemslist);
			return result;

		} catch (Exception e) {
			logger.error("分页查询字典子项出错，类型主键为：{}，查询关键字为：{}。", typeCode, itemKeyword);
			throw e;
		}
	}

	/**
	 * 加载数据字典子项对象，包括以下三种情况： 1、加载空子项；2、加载指定父子项的空子项；3、加载已存在的子项
	 * 
	 * @param typeId
	 *            类型主键
	 * @param ptypename
	 *            子项的父子项主键
	 * @param itemId
	 *            子项主键
	 * @return JSP页面地址
	 * @throws Exception
	 */
	@RequestMapping(value = "/inputItem")
	public String inputItem(String ptypeCode, String ptypename, String itemId, Model model) throws Exception {
		try {
			// 加载已存在的子项对象
			if (itemId != null && itemId.trim().length() > 0) {
				BscDicCodeItem item = bscDicCodeService.getItemByItemId(itemId);
				ptypename = new String(ptypename.getBytes("iso-8859-1"), "UTF-8");
				model.addAttribute("ptypename", ptypename);
				model.addAttribute("vo", item != null ? item : new BscDicCodeItem());
			}
			// 加载空子项对象
			else if (ptypeCode != null && ptypeCode.trim().length() > 0) {
				BscDicCodeItem item = new BscDicCodeItem();
				item.setTypeCode(ptypeCode);
				ptypename = new String(ptypename.getBytes("iso-8859-1"), "UTF-8");
				model.addAttribute("vo", item);
				model.addAttribute("ptypename", ptypename);
				if (logger.isDebugEnabled())
					logger.debug("已加载空子项，类型主键为：{}，父子项主键为：{}。", ptypeCode, ptypename);
			}

			// 参数关系有误抛出异常
			else
				throw new InvalidParameterMainError("ptypeCode", "ptypename", "itemId");

			return "/system/addDicItem";
		} catch (Exception e) {
			logger.error("加载数据字典子项对象出错，类型主键为：{}，父子项主键为：{}，子项主键为：{}。", ptypeCode, ptypename, itemId);
			throw e;
		}
	}

	/**
	 * 根据子项主键数组批量删除一个或多个子项对象
	 * 
	 * @param itemIds
	 *            子项主键数组
	 * @throws Exception
	 */
	@RequestMapping(value = "/deleteItemsCascade")
	@ResponseBody
	public Result deleteItemsCascade(String... typeId) throws Exception {
		try {
			int undeletedCount = bscDicCodeService.deleteItemsCascadeByItemIds(typeId);
			return ResultFormUtils.getSuccess(
					undeletedCount == 0 ? "已删除所有选中的字典子项。" : "已删除所有选中的未锁定字典子项，但有" + undeletedCount + "个子项因锁定状态无法删除！");
		} catch (Exception e) {
			logger.error("删除字典子项出错，子项主键数组为：{}。", com.tunan.utils.StringUtils.joinByComma(typeId));
			throw e;
		}
	}

	/**
	 * 保存字典子项form对象
	 * 
	 * @param form
	 *            字典子项form对象
	 * @param result
	 *            form对象验证结果
	 * @return Result对象
	 * @throws Exception
	 */
	@RequestMapping(value = "/saveItem")
	@ResponseBody
	public Result saveItem(@Valid BscDicCodeItem form, BindingResult result) throws Exception {
		try {
			if (result.hasErrors())
				throw new InvalidParameterMainError(ValidationUtils.convert(result));
			bscDicCodeService.saveItem(form);
			return ResultFormUtils.getSuccess("保存字典子项成功");
		} catch (Exception e) {
			logger.error("保存字典子项出错，form对象为：{}。", JsonUtils.toJson(form));
			throw e;
		}
	}

	/**
	 * 将附件上传至服务器磁盘的指定路径下
	 * 
	 * @param atPath
	 *            附件上传的服务器磁盘路径
	 * @param attachment
	 *            页面上传的附件对象
	 * @return true表示上传成功，false表示上传失败
	 */
	private boolean uploadFile(String atPath, MultipartFile attachment) {
		boolean result = false;

		if (attachment == null || attachment.getSize() == 0 || atPath == null || atPath.trim().length() == 0) {
			return result;
		}

		InputStream in = null;
		OutputStream out = null;

		try {
			// 文件路径格式处理
			atPath = atPath.replace('/', '\\');
			File dir = new File(atPath);
			// 如果文件目录不存在则创建
			if (dir.exists() == false) {
				dir.mkdirs();
			}

			// 删除目录下的所有文件
			String[] fileArray = dir.list();
			for (String filename : fileArray) {
				File deleteFile = new File(atPath + filename);
				deleteFile.delete();
			}

			// 输出附件
			File outputFile = new File(atPath + UPLOAD_FILE_NAME);

			int available = 0;
			in = new BufferedInputStream(attachment.getInputStream(), BUFFER_SIZE);
			out = new BufferedOutputStream(new FileOutputStream(outputFile), BUFFER_SIZE);
			byte[] buffer = new byte[BUFFER_SIZE];
			while ((available = in.read(buffer)) > 0) {
				if (available < BUFFER_SIZE) {
					out.write(buffer, 0, available);
				} else {
					out.write(buffer, 0, BUFFER_SIZE);
				}
			}
			result = true;// 上传附件成功
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (in != null) {
					in.close();
				}
				if (out != null) {
					out.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	/**
	 * 启用字典子项
	 * 
	 * @param itemId
	 *            子项主键
	 * @throws Exception
	 */
	@RequestMapping(value = "/enableItem")
	@ResponseBody
	public Result enableItem(String itemId) throws Exception {
		try {
			bscDicCodeService.updateItemIsActiveField(itemId, Status.ONE);

			return ResultFormUtils.getSuccess("启用成功");
		}
		catch (Exception e) {
			return ResultFormUtils.getFailure("启用失败");
		}
	}

	/**
	 * 禁用字典子项
	 * 
	 * @param itemId
	 *            子项主键
	 * @throws Exception
	 */
	@RequestMapping(value = "/disableItem")
	@ResponseBody
	public Result disableItem(String itemId) throws Exception {
		try {
			bscDicCodeService.updateItemIsActiveField(itemId, Status.ZERO);
			return  ResultFormUtils.getSuccess("禁用成功");
		}
		catch (Exception e) {
			return ResultFormUtils.getFailure("禁用失败");
		}
	}

	/**
	 * 获取字典子项列表
	 * 
	 * @param typeCode
	 *            类型编号
	 * @return 子项列表
	 * @throws Exception
	 */
	@RequestMapping(value = "/lgetItems")
	@ResponseBody
	public List<BasicCombo> lgetItems(String typeCode) throws Exception {
		try {
			List<BscDicCodeItem> list = bscDicCodeService.getActiveItemsByTypeCode(typeCode);
			return BscDicCodeConverter.convertCodeItemToBasicCombo(list, true);
		} catch (Exception e) {
			logger.error("获取字典子项列表出错，类型编号为：{}。", typeCode);
			throw e;
		}
	}

	/**
	 * 获取字典子项树结构
	 * 
	 * @param typeId
	 *            类型编号
	 * @return 子项列表
	 * @throws Exception
	 */
	@RequestMapping(value = "/tgetItems.do")
	@ResponseBody
	public List<BasicCombo> tgetItems(String typeId) throws Exception {
		try {
			List<BscDicCodeItem> list = bscDicCodeService.getAllItemsByTypeId(typeId);
			return BscDicCodeConverter.buildTreeCombo(list, true);
		} catch (Exception e) {
			logger.error("获取字典子项列表出错，类型编号为：{}。", typeId);
			throw e;
		}
	}

	/**
	 * 跳转到显示帮助信息页面
	 */
	@RequestMapping(value = "/showHelp.do")
	public String showHelp() {
		return "/bsc/dic/code/showHelp";
	}

	/**
	 * 查询所有类型
	 * 
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/getAllTypes")
	@ResponseBody
	public Result findAllTypes(@RequestParam(required = false, defaultValue = "1") Integer pageNum,
			@RequestParam(required = false, defaultValue = "10") Integer pageSize, String wfds) throws Exception {
		PageHelper.startPage(pageNum, pageSize);

		Map<String, Object> params = new HashMap<String, Object>();
		params.put("wfds", wfds);

		List<BscDicCodeType> typelist = bscDicCodeService.getAllTypes(params);
		Result result = new ResultWithPage<BscDicCodeType>(typelist);
		return result;
	}

	/**
	 * 检测typecode是否被占用
	 * 
	 * @param typeCode
	 * @return
	 * @throws Exception
	 */

	@RequestMapping(value = "/checkTypeCode")
	@ResponseBody
	public Result checkTypeCode(String typeCode) {
		try {
			BscDicCodeType scDicCodeType = bscDicCodeService.getTypeByTypeCode(typeCode);
			if (scDicCodeType != null) {
				return ResultFormUtils.getFailure("该编码类型已存在！");
			} else {
				return ResultFormUtils.getSuccess("编码类型可用！");
			}

		} catch (Exception e) {
			throw e;
		}
	}

		/**
		 * 
		 * @param plupload
		 * @param request
		 * @Description 上传
		 * @author lizhuo
		 */
	@RequestMapping(value = "/uploadAttach",method=RequestMethod.POST)
	public void uploadAttach( Plupload plupload,HttpServletRequest request, HttpServletResponse response   ) throws IOException {		
		plupload.setRequest(request);
		//文件存储路径
		File dir = new File(plupload.getRequest().getSession().getServletContext().getRealPath("/") + filePathConfig.getUrl());
		//System.out.println(dir.getPath());
		try {
			//上传文件
			PluploadUtil.upload(plupload, dir);
			//判断文件是否上传成功（被分成块的文件是否全部上传完成）
			if (PluploadUtil.isUploadFinish(plupload)) {
				System.out.println(plupload.getName() + "----");
			}
			
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}	
 }


	/**
	 * 
	 * @param typeCode
	 * @param itemCode
	 * @return Result
	 * @Description 跟据typeCode和itemCode查找
	 * @date 2016年4月11日
	 * @author kinda
	 */
	@RequestMapping(value = "/findDic", method = RequestMethod.GET)
	@ResponseBody
	public Result findDic(String typeCode, String itemCode) {
		Optional<String> OpTypeCode = Optional.ofNullable(typeCode);
		Optional<String> OpItemCode = Optional.ofNullable(itemCode);

		Map<String, Object> params = new HashMap<>();
		if (OpTypeCode.isPresent() && !"undefined".equalsIgnoreCase(OpTypeCode.get())) {
			params.put("typeCode", OpTypeCode.get().trim().toUpperCase());
		}
		if (OpItemCode.isPresent() && !"undefined".equalsIgnoreCase(OpItemCode.get())) {
			params.put("itemCode", OpItemCode.get().trim().toUpperCase());
		}
		List<BscDicCodeItem> selectByTypecodeAndItemode = bscDicCodeService.selectByTypecodeAndItemode(params);
		Result result = new ResultSuccess(selectByTypecodeAndItemode);
		return result;
	}

}
